package org.strieber.fca;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Set;

public class Substitution {

	String determinedValue = "";
	HashMap<String, ArrayList<String>> possibleValues = new HashMap<String, ArrayList<String>>();
	HashMap<String, ArrayList<String>> actualValues = new HashMap<String, ArrayList<String>>();
	StringBuffer results = new StringBuffer();
	
	public Substitution() {
		
	}
	
	public Substitution(String input) {
		processInput(input);
	}
	
	public void substitute() {
		
		Set<String> actualKeys = actualValues.keySet();
		Set<String> possibleKeys = possibleValues.keySet();
		
		for (String actualKey : actualKeys) {
			if (possibleKeys.contains(actualKey)) {
				int numOfActualValues = actualValues.get(actualKey).size();
				int numOfPossibleValues = possibleValues.get(actualKey).size();
				
				if (numOfActualValues == numOfPossibleValues) {
					// remove this value (don't add to results)
				}
				else if ((numOfPossibleValues - numOfActualValues) == 1) {
					// find the missing value and make !=
					ArrayList<String> actualEntries = actualValues.get(actualKey);
					ArrayList<String> possibleEntries = possibleValues.get(actualKey);
					
					for (int i = 0; i < possibleValues.size(); i++) {
						if (!actualEntries.contains(possibleEntries.get(i))) {
							// this is the missing value
							results.append(actualKey + "!: " + actualValues.get(actualKey) + " ");
						}
					}
					
				}
				else {
					// don't change anything
					results.append(actualKey + ": " + actualValues.get(actualKey) + " ");
				}
			}
		}
	}
	
	private void processInput(String input) {
		String attributes = input.split("] =>")[0].trim();
		attributes = attributes.substring(1, attributes.length()).trim();
		determinedValue = input.split("] =>")[1].trim();
		
		Scanner tokenizer = new Scanner(attributes);
		tokenizer.useDelimiter(" AND ");
		
		while (tokenizer.hasNext()) {
			
			String next = tokenizer.next();
			Scanner innerTokenizer = new Scanner(next);
			innerTokenizer.useDelimiter(" OR ");
			
			while (innerTokenizer.hasNext()) {
				String innerNext = innerTokenizer.next();
				String attributeName = innerNext.split("=")[0].trim();
				String attributeValue = innerNext.split("=")[1].trim();
				appendActualValue(attributeName, attributeValue);
			}
			
		}
	}
	
	public void appendPossibleValue(String attribute, String newValue) {
		if (possibleValues.containsKey(attribute)) {
			ArrayList<String> values = possibleValues.get(attribute);
			values.add(newValue);
			possibleValues.put(attribute, values);
		}
		else {
			ArrayList<String> values = new ArrayList<String>();
			values.add(newValue);
			possibleValues.put(attribute, values);
		}
	}
	
	private void appendActualValue(String attribute, String newValue) {
		if (actualValues.containsKey(attribute)) {
			ArrayList<String> values = actualValues.get(attribute);
			values.add(newValue);
			actualValues.put(attribute, values);
		}
		else {
			ArrayList<String> values = new ArrayList<String>();
			values.add(newValue);
			actualValues.put(attribute, values);
		}
	}
	
	public String getRules() {
		return results.toString();
	}
	
	public void printPossibleValues() {
		System.out.println("Printing possible values: ");
		Set<String> set = possibleValues.keySet();
		for (String value : set) {
			System.out.print(value + ": ");
			System.out.println(possibleValues.get(value));
		}
	}
	
	public void printActualValues() {
		System.out.println("Printing actual values: ");
		Set<String> set = actualValues.keySet();
		for (String value : set) {
			System.out.print(value + ": ");
			System.out.println(actualValues.get(value));
		}
	}
	
	public void printDeterminedValue() {
		System.out.println("determinedValue: " + determinedValue);
	}
	
	public static void main(String[] args) {
		Substitution sb = new Substitution();
		sb.appendPossibleValue("A", "1");
		sb.appendPossibleValue("A", "2");
		sb.appendPossibleValue("A", "3");
		
		sb.printPossibleValues();
	}
}
